#include "SHA256.h"
#include <endian.h>
#include <cstring>


/* This Algorithm treats byte array as big endian order integer(32bit).
 * If os/cpu architecture is little endian, transform it.
 */

void SHA256::byte_to_int(uint32_t *dest, const uint8_t *src, uint32_t ilen) {
	#if __BYTE_ORDER == __LITTLE_ENDIAN
	for(; ilen--; ++dest, src+=4) {
		*dest = (uint32_t) src[0]<<24 | src[1]<<16 | src[2]<<8 | src[3];
	}
	#else
	if ((const uint8_t*)dest!=src) memcpy(dest, src, (ilen)<<2);
	#endif
}

// transform each int(32bit) into 4-byte(big endian), ilen is length of int
void SHA256::int_to_byte(uint8_t *dest, const uint32_t *src, uint32_t ilen) {
	#if __BYTE_ORDER == __LITTLE_ENDIAN
	uint32_t *idest = (uint32_t*)dest;
	const uint8_t *bsrc = (const uint8_t*)src;
	for(; ilen--; ++idest, bsrc+=4) {
		*idest = (uint32_t)bsrc[0]<<24 | bsrc[1]<<16 | bsrc[2]<<8 | bsrc[3];
	}
	#else
	if (dest!=(uint8_t*)src) memcpy(dest, src, (ilen)<<2);
	#endif
}


//round constants
static const uint32_t K[64] = {
	 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
	 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
	 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
	 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
	 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
	 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
	 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
	 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
	 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
	 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
	 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
	 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
	 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
	 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
	 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
	 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
};

void SHA256::transform(const uint8_t *block) {
	register uint32_t a=mDigest[0], b=mDigest[1], c=mDigest[2], d=mDigest[3],
		e=mDigest[4], f=mDigest[5], g=mDigest[6], h=mDigest[7];
	// transform 4-byte into int(32bit)
	byte_to_int((uint32_t *)mBuffer, block, 16);
	uint32_t *buf = (uint32_t *)mBuffer;
	uint32_t s, t;

#define F1(x, y, z) (z ^ (x & (y ^ z)))
#define F2(x, y, z) ((x & y) | (z & (x | y)))
// recycle rotate 4-byte(32bit)
#define ROL(x, n) ( ((x) << (n)) | ((x) >> (32-(n))) )
#define S1(x) (ROL(x, 25) ^ ROL(x, 14) ^ (x>>3))
#define S2(x) (ROL(x, 15) ^ ROL(x, 13) ^ (x>>10))
#define S3(x) (ROL(x, 30) ^ ROL(x, 19) ^ ROL(x, 10))
#define S4(x) (ROL(x, 26) ^ ROL(x, 21) ^ ROL(x, 7))

#define BUF(i) (buf[i&15] += S1(buf[(i-15)&15]) + \
		buf[(i-7)&15] + S2(buf[(i-2)&15]))

#define STEP1(a, b, c, d, e, f, g, h, i) (s=S3(a)+F2(a, b, c), \
		t=S4(e)+F1(e, f, g)+h+K[i]+buf[i], d+=t, h=s+t)

#define STEP2(a, b, c, d, e, f, g, h, i) (s=S3(a)+F2(a, b, c), \
		t=S4(e)+F1(e, f, g)+h+K[i]+BUF(i), d+=t, h=s+t)
	
	STEP1(a, b, c, d, e, f, g, h, 0);
	STEP1(h, a, b, c, d, e, f, g, 1);
	STEP1(g, h, a, b, c, d, e, f, 2);
	STEP1(f, g, h, a, b, c, d, e, 3);
	STEP1(e, f, g, h, a, b, c, d, 4);
	STEP1(d, e, f, g, h, a, b, c, 5);
	STEP1(c, d, e, f, g, h, a, b, 6);
	STEP1(b, c, d, e, f, g, h, a, 7);
	STEP1(a, b, c, d, e, f, g, h, 8);
	STEP1(h, a, b, c, d, e, f, g, 9);
	STEP1(g, h, a, b, c, d, e, f, 10);
	STEP1(f, g, h, a, b, c, d, e, 11);
	STEP1(e, f, g, h, a, b, c, d, 12);
	STEP1(d, e, f, g, h, a, b, c, 13);
	STEP1(c, d, e, f, g, h, a, b, 14);
	STEP1(b, c, d, e, f, g, h, a, 15);

	STEP2(a, b, c, d, e, f, g, h, 16);
	STEP2(h, a, b, c, d, e, f, g, 17);
	STEP2(g, h, a, b, c, d, e, f, 18);
	STEP2(f, g, h, a, b, c, d, e, 19);
	STEP2(e, f, g, h, a, b, c, d, 20);
	STEP2(d, e, f, g, h, a, b, c, 21);
	STEP2(c, d, e, f, g, h, a, b, 22);
	STEP2(b, c, d, e, f, g, h, a, 23);
	STEP2(a, b, c, d, e, f, g, h, 24);
	STEP2(h, a, b, c, d, e, f, g, 25);
	STEP2(g, h, a, b, c, d, e, f, 26);
	STEP2(f, g, h, a, b, c, d, e, 27);
	STEP2(e, f, g, h, a, b, c, d, 28);
	STEP2(d, e, f, g, h, a, b, c, 29);
	STEP2(c, d, e, f, g, h, a, b, 30);
	STEP2(b, c, d, e, f, g, h, a, 31);

	STEP2(a, b, c, d, e, f, g, h, 32);
	STEP2(h, a, b, c, d, e, f, g, 33);
	STEP2(g, h, a, b, c, d, e, f, 34);
	STEP2(f, g, h, a, b, c, d, e, 35);
	STEP2(e, f, g, h, a, b, c, d, 36);
	STEP2(d, e, f, g, h, a, b, c, 37);
	STEP2(c, d, e, f, g, h, a, b, 38);
	STEP2(b, c, d, e, f, g, h, a, 39);
	STEP2(a, b, c, d, e, f, g, h, 40);
	STEP2(h, a, b, c, d, e, f, g, 41);
	STEP2(g, h, a, b, c, d, e, f, 42);
	STEP2(f, g, h, a, b, c, d, e, 43);
	STEP2(e, f, g, h, a, b, c, d, 44);
	STEP2(d, e, f, g, h, a, b, c, 45);
	STEP2(c, d, e, f, g, h, a, b, 46);
	STEP2(b, c, d, e, f, g, h, a, 47);

	STEP2(a, b, c, d, e, f, g, h, 48);
	STEP2(h, a, b, c, d, e, f, g, 49);
	STEP2(g, h, a, b, c, d, e, f, 50);
	STEP2(f, g, h, a, b, c, d, e, 51);
	STEP2(e, f, g, h, a, b, c, d, 52);
	STEP2(d, e, f, g, h, a, b, c, 53);
	STEP2(c, d, e, f, g, h, a, b, 54);
	STEP2(b, c, d, e, f, g, h, a, 55);
	STEP2(a, b, c, d, e, f, g, h, 56);
	STEP2(h, a, b, c, d, e, f, g, 57);
	STEP2(g, h, a, b, c, d, e, f, 58);
	STEP2(f, g, h, a, b, c, d, e, 59);
	STEP2(e, f, g, h, a, b, c, d, 60);
	STEP2(d, e, f, g, h, a, b, c, 61);
	STEP2(c, d, e, f, g, h, a, b, 62);
	STEP2(b, c, d, e, f, g, h, a, 63);
	
	mDigest[0]+=a, mDigest[1]+=b, mDigest[2]+=c, mDigest[3]+=d, 
	mDigest[4]+=e, mDigest[5]+=f, mDigest[6]+=g, mDigest[7]+=h;
}

void SHA256::init() {
	mDigest[0] = 0x6a09e667;
	mDigest[1] = 0xbb67ae85;
	mDigest[2] = 0x3c6ef372;
	mDigest[3] = 0xa54ff53a;
	mDigest[4] = 0x510e527f;
	mDigest[5] = 0x9b05688c;
	mDigest[6] = 0x1f83d9ab;
	mDigest[7] = 0x5be0cd19;
	mBufferSizeLow = mBufferSizeHigh = 0;
}

void SHA256::update(const void *data, unsigned int size) {
	// update bit count
	uint32_t low = mBufferSizeLow;
	mBufferSizeLow += size<<3;
	if (mBufferSizeLow<low) mBufferSizeHigh++;	// carry from low to high
	mBufferSizeHigh += size>>29;
	// handle any leading odd-sized chunks
	const uint8_t *buf = (const uint8_t*)data;
	uint32_t offset = (low>>3) & 63;
	if (offset) {
		if (size<64-offset) {
			memcpy(mBuffer+offset, buf, size);
			return;
		}
		memcpy(mBuffer+offset, buf, 64-offset);
		buf += 64-offset;
		size -= 64-offset;
		transform(mBuffer);
	}
	// process data in 64-byte chunks
	for(; size>63; size-=64, buf+=64) {
		transform(buf);
	}
	// handle any remaining bytes of data. 
	memcpy(mBuffer, buf, size);
}

void SHA256::final() {
	uint32_t offset = (mBufferSizeLow >3) & 63;
	mBuffer[offset++] = 0x80;
	// current chunk no more space to store last Bitcount,
	// fill last space as zero, and digest this chunk.
	if (offset>56) {
		memset(mBuffer+offset, 0, 64-offset);
		offset = 0;
		transform(mBuffer);
	}
	// fill first padding 56-byte, copy Bitcount to last 8-byte
	memset(mBuffer+offset, 0, 56-offset);
	int_to_byte(mBuffer+56, &mBufferSizeHigh, 1);
	int_to_byte(mBuffer+60, &mBufferSizeLow, 1);
	transform(mBuffer);
	// message digest result
	int_to_byte((uint8_t*)mDigest, mDigest, 8);
	// clear sensitive message
	memset(mBuffer, 0, sizeof(mBuffer));
	mBufferSizeLow = mBufferSizeHigh = 0;
}